package net.bingosoft.common.data;

import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import net.bingosoft.common.json.JSONArray;
import net.bingosoft.common.json.JSONObject;

import org.ecside.table.limit.Limit;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;

import bingo.persister.Persister;
/**
 * 2008-1-16 下午01:20:26
 * Author:yangdongyu(yangdy@bingosoft.net)
 * ReadMe:dao基类,提供最常用的数据库访问操作
 * ChangeLog:
 */
public interface BaseDao {
    /**
     * 获取Persister,Persister是一个敏捷的ORM工具,能够方便快捷的完成基于单表的数据操作
     * @return Persister
     */
	Persister getPersister();

	/**
	 * 设置Persister
	 * @param persister
	 */
	void setPersister(Persister persister);

	/**
	 * 获取建立在指定数据源之上的Persister对象
	 * @param datasourceKey 数据源在Spring配置文件中的键值(beanId）
	 * @return
	 */
	Persister getPersister(String datasourceKey);

	/**
	 * 获取指向指定数据源源的BaseDao，使我们通过一个dao实现对其他数据源的数据访问
	 * @param datasourceKey
	 * @return
	 */
	BaseDao getBaseDao(String datasourceKey);

	/**
	 * 保存指定对象
	 * @param obj 待保存对象
	 * @return 更新记录数,一般更新成功返回1
	 */
	int save(Object obj);

	/**
	 * 更新指定对象
	 * @param obj 待更新对象
	 * @return 更新记录数,一般更新成功返回1
	 */
	int update(Object obj);

	/**
	 * 删除指定对象
	 * @param obj 待删除对象
	 * @return 删除记录数目
	 */
	int delete(Object obj);

	/**
	 * 通过对象类型和对象标识删除对象,支持复合主键
	 * @param <T>
	 * @param objType
	 * @param id
	 * @return 删除记录数目
	 */
	<T> int delete(Class<T> objType, Object id);
	
	/**
	 * 获取当前操作使用的数据库连接
	 * @return
	 * @throws SQLException 
	 */
	Connection currentConnection() throws SQLException;
	/**
	 * 从数据源获取一个新的连接,需要自己关闭
	 * @return
	 * @throws SQLException 
	 */
	Connection newConnection() throws SQLException;
	/**
	 * 通过Id获取指定类型的对象
	 * @param <T> 泛型参数
	 * @param clazz
	 * @param id
	 * @return
	 */
	<T> T load(Class<T> clazz, Object id);
	/**
	 * 通过sql查询获取一个json对象
	 * @param sql 查询的sql
	 * @param params 查询参数
	 * @return
	 */
	JSONObject getJSON(String sql,Object ...params);
	
	/**
	 * 通过sql查询获取一个json数组对象
	 * @param sql 查询的sql
	 * @param params 查询参数
	 * @return JSONArray
	 */
	JSONArray getJSONArray(String sql,Object ...params);
	/**
	 * 根据sql语句获取一个值对象(ValueBean),值对象是对Map的简单包装,提供一些获取特定数据类型的方法
	 * @param sql
	 * @param params
	 * @return
	 */
	ValueBean get(String sql,Object ...params);

	/**
	 * 通过Sql获取指定类型的对象,可以从多个表中查询,返回类型可以是基本数据类型,也可以是用户定义类型
	 * @param <T> 泛型参数
	 * @param returnType 返回对象的类型参数
	 * @param customSQL sql查询语句
	 * @param params 查询参数
	 * @return
	 */
	
	<T> T get(final Class<T> returnType, final String customSQL,
			final Object... params);

	/**
	 * 通过SQL获取指定类型对象的列表,可以从多个表中查询,返回类型可以是基本数据类型,也可以是用户定义类型
	 * @param <T> 泛型参数
	 * @param returnType
	 * @param customSQL
	 * @param params
	 * @return
	 */
	
	<T> List<T> list(final Class<T> returnType, final String customSQL,
			final Object... params);
	/**
	 * 根据给定的查询语句和参数,查询获取ValueBean的列表
	 * @param customSQL
	 * @param params
	 * @return
	 */
	List<ValueBean> listValueBeans(final String customSQL,
			final Object... params);
	
	/**
	 * 通过sql执行数据插入
	 * @param sql 数据插入语句
	 * @param params
	 * @return 更新记录数
	 */
	
	int insert(final String sql, final Object... params);

	/**
	 * 通过sql执行数据库更新
	 * @param sql
	 * @param params
	 * @return 更新记录数
	 */
	
	int update(final String sql, final Object... params);
	
	/**
	 * 通过sql执行数据库删除
	 * @param sql
	 * @param params
	 * @return 删除记录数目
	 */
	
	int delete(final String sql, final Object... params);

	/**
	 * 通过sql读取一个Map列表,Map的键值为读取ResultSet的字段名称,值为字段的值
	 * @param sql
	 * @param params
	 * @return
	 */
	
	List<Map<String, Object>> list(final String sql, final Object... params);
	
	
	/**
	 * 通过动态SQL语句的键值和对应的参数bean查询一个Map列表,Map的键值为读取ResultSet的字段名称,值为字段的值
	 * @param customSQL 动态SQL语句的key值
	 * @param paramBean 包含查询参数的参数对应,可以是Map或者Javabean
	 * @return List<Map<String,Object>>
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	List<Map<String,Object>> listByDynamicSQL(final String customSQL,final Object paramBean) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException;
	
	/**
	 * 通过动态SQL进行查询
	 * @param <T>
	 * @param returnType
	 * @param customSQL
	 * @param args
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	<T> List<T> listByDynamicSQL(final Class<T> returnType,final String customSQL,final Object... args)throws Exception;
	/**
	 * 通过动态sql进行分页查询,返回一个map列表
	 * @param sqlKey sql查询语句在配置文件中的键值
	 * @param paramBean 参数对象
	 * @param limit ectable的分页对象,据此对象可以获取ectable的排序及过滤信息
	 * @return 查询结果列表
	 * @throws Exception
	 */
	List<Map<String, Object>> pageQueryByDynamicSQL(String sqlKey,
			Object paramBean, Limit limit) throws Exception;
	
	/**
	 * 通过动态sql进行分页查询,返回一个map列表(提供优化功能)
	 * @param sqlKey sql查询语句在配置文件中的键值
	 * @param paramBean 参数对象
	 * @param limit ectable的分页对象,据此对象可以获取ectable的排序及过滤信息
	 * @param optimize 是否对查询总数的查询语句进行优化,比如简化查询内容,去除Order By语句,
	 * 			如果optimize = false,则不进行任何优化,直接在查询内容的SQL包装一层进行总数查询
	 * @return 查询结果列表
	 * @throws Exception
	 */
	List<Map<String, Object>> pageQueryByDynamicSQL(String sqlKey,
			Object paramBean, Limit limit,boolean optimize) throws Exception;
	/**
	 * 通过动态sql或动态sql的键值及参数Bean进行查询
	 * @param sqlOrKey sql语句或sql语句在SQLProvider中的键值
	 * @param paramBean 参数对象
	 * @return
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 */
	List<Map<String, Object>> queryByDynamaicSQL(String sqlOrKey,Object paramBean) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException;

	/**
	 * 通过sql进行分页查询,获取一个map列表
	 * @param pager
	 * @param sqlKey
	 * @param sqlParams
	 * @return
	 * @throws Exception
	 */
	
	List<Map<String, Object>> pageQueryBySQL(Pager pager, String sqlKey,
			Object... sqlParams) throws Exception;

	/**
	 * 通过sql进行分页查询,返回指定类型对象列表
	 * @param <T> 泛型参数
	 * @param pager
	 * @param returnType
	 * @param sqlKey
	 * @param sqlParams
	 * @return
	 * @throws Exception
	 */
	
	<T> List<T> pageQueryBySQL(Pager pager, Class<T> returnType, String sqlKey,
			Object... sqlParams) throws Exception;

	/**
	 * 获取代码表
	 * @param sqlId
	 * @param params
	 * @return
	 */
	Map<String, String> getCodeMap(String sqlId, Object... params);

	/**
	 * 设置beanFacotry
	 * @param beanFacotry
	 * @throws BeansException
	 */
	void setBeanFactory(BeanFactory beanFacotry) throws BeansException;

	/**
	 * 获取指定beanId的数据源
	 * @param dsKey
	 * @return
	 */
	DataSource getDataSource(String dsKey);

	/**
	 * 获取默认序列
	 * @return
	 */
	Long getSequence();

	/**
	 * 获取指定名称的序列
	 * @param sequenceName
	 * @return
	 */
	Long getSequence(String sequenceName);

	/**
	 * 执行一个存储过程
	 * @param procedureName
	 * @param inputParams
	 * @throws SQLException
	 */
	void executeProcedure(String procedureName, Object[] inputParams)
			throws SQLException;
	
	/**
	 * 执行一个没有输入和输出参数的存储过程
	 * @param procedureName
	 * @throws SQLException
	 */
	void executeProcedure(String procedureName)
			throws SQLException;
	/**
	 * 执行指定的存储过程
	 * @param procedureName 存储过程的名称
	 * @param inputParams 输入参数数组
	 * @param outParamTypes 输出参数类型数组(Types常量,如java.sql.Types.INTEGER)
	 * @return 存储过程的执行结果
	 * @throws SQLException
	 */
	Object[] executeProcedure(String procedureName,Object[] inputParams,int ...outParamTypes) throws SQLException;
	/**
	 * 执行指定的存储过程,需要用户在CallableStatementProcessor中注册存储过程参数和获取执行结果
	 * @param procedureName 存储过程名字
	 * @param processor CallableStatement处理器,用于在存储过程调用中注册参数和获取执行结果
	 * @param inputParams 存储过程的参数
	 * @return 存储过程的返回结果
	 * @throws SQLException
	 */
	Object executeProcedure(String procedureName,ICallableStatementProcessor processor,Object... inputParams) throws SQLException;
	/**
	 * 在指定数据源上执行指定的存储过程
	 * @param dataSourceKey 数据源的键值
	 * @param procedureName 存储过程的名称
	 * @param inputParams 入参
	 * @throws SQLException
	 */
	void executeProcedureOnDatasource(String dataSourceKey, String procedureName,
			Object... inputParams) throws SQLException;

	/**
	 * 获取spring配置文件中默认的数据源
	 * @return
	 */
	DataSource getDatasource();

	/**
	 * 设置指定的数据源
	 * @param datasource
	 */
	void setDatasource(DataSource datasource);

	/**
	 * 通过指定的sql语句和参数读取特定类型的对象,支持基本数据类型和用户自定义的数据类型
	 * @param <T>  泛型参数
	 * @param type 返回结果类型
	 * @param sql sql查询语句
	 * @param params sql查询参数
	 * @return
	 */
	<T> T readScalar(Class<? extends T> type, String sql, Object... params);
	/**
	 * 根据查询语句和参数,查询获取一个字符串类型的对象
	 * @param sql 查询语句 
	 * @param params 查询参数
	 * @return
	 */
	String readString(String sql, Object... params);

    /**
     * 根据sql语句获取一个Map<String,Object>,键为结果集字段名称,值为结果集的字段值
     * @param sql
     * @param params
     * @return
     */
	Map<String,Object> readMap(String sql,Object ...params);
	
    /**
     * 通过给定的表名和主键将对应的记录读入的Map 中
     * @param tableName 表的名称
     * @param primaryKeyColumnName 主键字段的名称
     * @param primaryKeyValue 主键字段的值
     * @return
     */
	Map<String,Object> readMapByTableNameAndPrimaryKey(String tableName,String primaryKeyColumnName,Object primaryKeyValue);
	
	/**
	 * 检查指定类型的对象是否存在
	 * @param obj 对象类型
	 * @param id 对象id
	 * @return
	 */
	boolean exists(Class obj,Object id);
	
	/**
	 * 通过Sql检查指定对象是否存在
	 * @param sql 查询sql
	 * @param params sql查询参数
	 * @return 查询结果是否存在
	 */
	boolean exists(String sql,Object ...params);
	
	/**
	 * Execute a named query binding a number of values to "?" parameters
	 * in the query string.
	 * <p>A named query is defined in a sql property file
	 * @param queryName the key of a query in a sql property file
	 * @param values the values of the parameters
	 * @return a {@link List} containing the results of the query execution
	 */
	List <Map<String,Object>>findByNamedQuery(String queryName, Object... values);
	
	/**
	 * 开启一个新的事务
	 *
	 */
	void begin();

	/**
	 * 提交当前事务
	 *
	 */
	void commit();

	/**
	 * 事务会滚
	 *
	 */
	void rollback();
	
	/**
	 * 从数据库获取一个guid字符串
	 * @return
	 */
	String getGUID();
	/**
	 * 根据表名和字段名称到值的映射自动生成插入语句将值放入数据库
	 * @param tableName 表的名称
	 * @param columnName 表的字段名到值的映射
	 */
	int save(String tableName,Map<String,Object> columnName);
	/**
	 * 通过表名和要更新的字段及字段的值和键及键的值进行数据更新
	 * @param tableName 表的名称
	 * @param columnNames 待更新的表的字段名到值的映射
	 * @param keyMap 表的键名称与值的map
	 */
	int updateByMap(String tableName,Map<String, Object> columnNames,Map<String,Object> keyMap);
	
	/**
	 * 通过表名和要更新的字段及字段的值和键及键的值进行数据更新
	 * @param tableName 表的名称
	 * @param columnNames 待更新的表的字段名到值的映射
	 * @param primaryKeyColumnName 主键字段的名称（主键字段的名称包含在columnNames中）
	 */
	int updateByMap(String tableName,String primaryKeyColumnName,Map<String, Object> columnNames);
	
	
	/**
	 * 通过SQL语句进行分页查询
	 * @param sqlKey sql语句或sql语句在sql.xml中的键值
	 * @param sqlParams sql查询语句的参数
	 * @param limit 分页查询对象
	 * @param showAllRecords 是否显示所有记录
	 * @return List<Map<String,Object>> 一页记录结果
	 * @throws Exception
	 */
	List<Map<String,Object>> pageQueryBySQL(String sqlKey,Object[] sqlParams,Limit limit,boolean showAllRecords)throws Exception;
	
	
	/**
	 * 通过表名称和主键对删除记录
	 * @param tableName
	 * @param keyMap
	 * @return
	 */
	int deleteByTableNameAndKeyMap(String tableName,Map <String,Object> keyMap);
	
	/**
	 * 通过表名称和主键对删除记录,该方法只适用于只有一个主键的表
	 * @param tableName 待删除记录所在表名称
	 * @param primaryKeyColumnName 主键字段的名称
	 * @param primaryKeyValue 主键字段的值
	 * @return
	 */
	int deleteByTableNameAndPrimaryKey(String tableName,String primaryKeyColumnName,Object primaryKeyValue);
	
	
	/**
	 * 通过动态SQL进行分页查询(通过参数提供的查询内容和查询总数的SQL语句进行分页查询)
	 * @param querySQLKey 查询语句在sql配置文件中的key值
	 * @param paramBean 构建查询语句所需的查询参数对象
	 * @param countSQLKey 查询总数的查询语句在sql配置文件中的key值
	 * @param countParamBean 查询总数的SQL语句所需的参数对象
	 * @param limit 分页对象
	 * @return
	 * @throws Exception
	 */
	List<Map<String,Object>> pageQueryByDynamicSQL(String querySQLKey,Object paramBean,String countSQLKey,Object countParamBean,Limit limit) throws Exception;
	
	/**
	 * 通过动态SQL进行分页查询(通过参数提供的查询内容和查询总数的SQL语句进行分页查询)
	 * @param querySQLKey 查询语句在sql配置文件中的key值
	 * @param paramBean 构建查询语句所需的查询参数对象
	 * @param countSQLKey 查询总数的查询语句在sql配置文件中的key值
	 * @param countParamBean 查询总数的SQL语句所需的参数对象
	 * @param limit 分页对象
	 * @param totalCount 总的数据条数,如果该值不为空,则分页查询不在进行查询总数的操作,直接使用该值
	 * @return
	 * @throws Exception
	 */
	List<Map<String,Object>> pageQueryByDynamicSQL(String querySQLKey,Object paramBean,String countSQLKey,Object countParamBean,Limit limit,Integer totalCount) throws Exception;
	
	
	//----------------------------------------------------------------------------
//	/**
//	 * 保存或更新对象,返回创建或更新对象的主键值
//	 * @param object
//	 */
//	Object saveOrUpdate(IdAware object);
//	/**
//	 * 通过表名称和主键列表批量删除记录
//	 * @param tableName 待删除记录所属的表
//	 * @param keyMapCollection 待删除记录的主键列表Map<String,Object> (Map.key为主键名称,Map.value 为主键值)
//	 * @return
//	 */
//	int batchDeleteByTableNameAndKeyMap(String tableName,Collection<Map <String,Object>> keyMapCollection);
//	
//	/**
//	 * 通过表名和要更新的记录的主键的Map到值的Map的映射列表进行数据更新
//	 * @param tableName 表的名称
//	 * @param keyMap2ValueMap 待更新的记录主键映射到值映射的列表
//	 */
//	void batchUpdate(String tableName,Collection<Map <Map<String,Object>,Map<String,Object>>> keyMap2ValueMap);
//
//	/**
//	 * 根据表名和字段名称到值的映射列表自动生成插入语句将值批量放入数据库
//	 * @param tableName 待保存记录所在表的名称
//	 * @param columnName2ValueMapList 表的字段名到值的映射列表,一个Map代表一条记录
//	 */
//	void batchSave(String tableName,Collection<Map <String,Object>> columnName2ValueMapList);
}